/* Copyright (c) 2016-2020 Enfry Ltd. All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of Enfry. 
 * You shall not disclose such Confidential Information
 * and shall use it only in accordance with the terms of the agreements
 * you entered into with Enfry.
 */
package com.enfry.storage.api;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.dao.DataAccessException;

import com.enfry.storage.common.Constants;
import com.enfry.storage.common.StorageUtils;
import com.enfry.storage.exception.ExCode;
import com.enfry.storage.exception.StorageException;
import com.enfry.storage.core.pool.Fastdfs;

public class FileOperateImpl extends BaseApi implements IFileOperate {

	@Resource
	private Fastdfs fastdfs;

	@Override
	public String upload(InputStream inputStream, long fileSize,
			String fileExtName) {
		try {
			String fileCode = fastdfs.uploadFile(null, fileSize, inputStream,
					fileExtName, null);
			logger.info("upload file_id:" + fileCode);

			if (fileCode == null)
				throw new StorageException(ExCode.FASTDFS_UPLOAD);
			return fileCode;
		} catch (IOException e) {
			throw new StorageException(ExCode.FASTDFS_UPLOAD_IO, e);
		} catch (Exception e) {
			throw new StorageException(ExCode.FASTDFS_UPLOAD, e);
		}
	}

	@Override
	public String upload(byte[] fileBytes, String fileExtName) {
		String fileCode;
		try {
			fileCode = fastdfs.uploadFile(fileBytes, fileExtName, null);

			logger.info("upload file_id:" + fileCode);

			if (fileCode == null)
				throw new StorageException(ExCode.FASTDFS_UPLOAD);

			return fileCode;
		} catch (IOException e) {
			throw new StorageException(ExCode.FASTDFS_UPLOAD_IO, e);
		} catch (Exception e) {
			throw new StorageException(ExCode.FASTDFS_UPLOAD, e);
		}
	}

	@Override
	public String uploadSlave(String appKey, String masterFileCode,
			byte[] fileBytes, String prefix, String fileExtName) {
		String thumbCode;
		try {
			thumbCode = fastdfs.uploadFile(masterFileCode, prefix, fileBytes,
					fileExtName, null);

			logger.info("upload file_id:" + thumbCode);

			if (thumbCode == null)
				throw new StorageException(ExCode.FASTDFS_UPLOAD);

			// 保存缩略图与主图关系
			Map<String, Object> thumbMap = new HashMap<>();
			thumbMap.put("thumbId", this.getNextId());
			thumbMap.put("thumbCode", thumbCode);
			thumbMap.put("fileCode", masterFileCode);
			thumbMap.put("appKey", appKey);
			sqlMap.insert("storage.thumb.insert", thumbMap);

			return thumbCode;
		} catch (IOException e) {
			throw new StorageException(ExCode.FASTDFS_UPLOAD_IO, e);
		} catch (Exception e) {
			throw new StorageException(ExCode.FASTDFS_UPLOAD, e);
		}
	}

	@Override
	public byte[] download(String fileCode) {
		try {
			return fastdfs.downloadFile(fileCode);
		} catch (IOException e) {
			throw new StorageException(ExCode.FASTDFS_DOWNLOAD_IO, e);
		} catch (Exception e) {
			throw new StorageException(ExCode.FASTDFS_DOWNLOAD, e);
		}

	}

	@Override
	public void download(String fileCode, OutputStream outputStream) {
		try {
			int errno = fastdfs.downloadFile(fileCode, outputStream);

			if (errno != 0) {
				logger.error("存储系统内部错误：" + errno);
				throw new StorageException(ExCode.FASTDFS_DOWNLOAD, errno);
			}
		} catch (IOException e) {
			throw new StorageException(ExCode.FASTDFS_DOWNLOAD_IO, e);
		} catch (Exception e) {
			throw new StorageException(ExCode.FASTDFS_DOWNLOAD, e);
		}
	}

	@Override
	public void delete(String fileCode) {
		try {
			int errno = fastdfs.deleteFile(fileCode);
			if (errno != 0) {
				logger.error("存储系统内部错误：" + errno);
				throw new StorageException(ExCode.FASTDFS_DELETE, errno);
			}

			// 查询缩略图
			List<Map<String, Object>> thumbList = sqlMap.queryForList(
					"storage.thumb.selectByCode", fileCode);
			// 删除缩略图
			for (Map<String, Object> thumb : thumbList) {
				fastdfs.deleteFile((String) thumb.get("thumbCode"));
			}
			sqlMap.delete("storage.thumb.deleteByCode", fileCode);
		} catch (DataAccessException e) {
			throw new StorageException(ExCode.DB_ERR, e);
		} catch (IOException e) {
			throw new StorageException(ExCode.FASTDFS_DELETE_IO, e);
		} catch (Exception e) {
			throw new StorageException(ExCode.FASTDFS_DELETE, e);
		}
	}

	@Override
	public List<String> deleteBatch(String[] fileCodes) {
		try {
			Map<String, Object> param = new HashMap<>();
			param.put("fileCodes", fileCodes);
			List<Map<String, Object>> fileList = sqlMap.queryForList(
					"storage.thumb.select", param);
			Iterator<Map<String, Object>> iterator = fileList.iterator();

			List<String> ids = new ArrayList<>();
			List<String> errorIds = new ArrayList<>();
			while (iterator.hasNext()) {
				Map<String, Object> fileMap = iterator.next();
				String fileCode = (String) fileMap.get("fileCode");
				logger.debug("fileCode:" + fileCode);

				int errno = fastdfs.deleteFile(fileCode);
				if (errno != 0) {
					logger.error("删除：" + fileCode + "，存储系统内部错误：" + errno);
					errorIds.add((String) fileMap.get("id"));
				} else {
					ids.add((String) fileMap.get("id"));
				}
			}

			param = new HashMap<>();
			param.put("ids", ids);
			sqlMap.delete("storage.thumb.delete", ids);

			return errorIds;
		} catch (DataAccessException e) {
			throw new StorageException(ExCode.DB_ERR, e);
		} catch (IOException e) {
			throw new StorageException(ExCode.FASTDFS_DELETE_IO, e);
		} catch (Exception e) {
			throw new StorageException(ExCode.FASTDFS_DELETE, e);
		}
	}

	@Override
	public String getIMGUrl(String serverUrl, String fileCode, String appKey,
			String appSecret) {
		try {
			Map<String, Object> param = new HashMap<>();
			param.put("appKey", appKey);
			param.put("ts", Constants.GET_IMG_TS);
			param.put("fileCode", fileCode);

			return StorageUtils.getSecretUrl(serverUrl, "img.api", appSecret,
					param);
		} catch (IOException e) {
			throw new StorageException(ExCode.SIGN_IO_ERR);
		}
	}
}
